#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import asyncore
import logging
import socket
import struct
from asyncore import dispatcher
from threading import Thread

from net.msg import EventType
from net.msg import MsgCtx
from net.msg import NetAdapter
from net.utils import utf8_decode
from net.utils import utf8_encode

logging.getLogger().setLevel(logging.INFO)


class CliHandler(dispatcher):

    def __init__(self, host='localhost', port=10110, adapter=NetAdapter()):
        dispatcher.__init__(self)
        self.adapter = adapter
        self.host = host
        self.port = port

    def start(self):
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.connect((self.host, self.port))

    def handle_connect(self):
        logging.info('connect server %s success', self.addr)

    def handle_close(self):
        logging.info('connect close %s', self.addr)
        self.close()

    def handle_read(self):
        raw_msglen = super(CliHandler, self).recv(4)
        if not raw_msglen:
            return None
        msglen = struct.unpack('>I', raw_msglen)[0]
        data = utf8_decode(super(CliHandler, self).recv(msglen))
        self.adapter.handle_data(handler=self, data=data)

    def send(self, data):
        if data is not None:
            bin_msg = utf8_encode(data)
            msg = struct.pack('>I', len(bin_msg)) + bin_msg
            super(CliHandler, self).send(msg)

    def send_cmd(self, cmd=EventType.DATA, data=None):
        json_data = MsgCtx(cmd=cmd, data=data).to_json()
        self.send(data=json_data)


class NetCli(object):

    def __init__(self, host='localhost', port=10110, adapter=NetAdapter()):
        self.handler = CliHandler(host=host, port=port, adapter=adapter)
        self.t = Thread(target=(lambda: asyncore.loop()), daemon=True)

    def start(self):
        self.handler.start()
        self.t.start()

    def stop(self):
        pass


class PrintAdapter(NetAdapter):
    def __init__(self):
        pass

    def handle_data(self, handler, data):
        logging.debug(data)
        ctx = MsgCtx.ctx_from_json(data)
        if ctx.cmd == EventType.INIT:
            self.do_init(handler=handler, data=ctx.data)
        if ctx.cmd == EventType.DATA:
            self.do_print(handler=handler, data=ctx.data)

    def do_init(self, handler, data):
        logging.info('session_id=%s', data)

    def do_print(self, handler, data):
        logging.info(data)


if __name__ == '__main__':
    import time

    cli = NetCli(adapter=PrintAdapter())
    cli.start()
    names = ['Cathy', 'Julie', 'Tenchael']
    for _name in names:
        cli.handler.send_cmd(cmd=EventType.DATA, data=_name)

    time.sleep(1)
    cli.handler.send_cmd(cmd=EventType.DATA, data='bye')
    time.sleep(1)
    logging.info('end')
